#include <stdio.h>
#include <stdlib.h>
#include <libfdt.h>

void parse_node(const void *fdt, int offset, int depth, FILE *output) {
    const char *name;
    int next_offset;
    int property_offset;

    // 获取节点名称
    name = fdt_get_name(fdt, offset, NULL);
    for (int i = 0; i < depth; ++i) {
        fprintf(output, "  ");
    }
    fprintf(output, "/%s\n", name);

    // 遍历属性
    fdt_for_each_property_offset(property_offset, fdt, offset) {
        const struct fdt_property *prop;
        const char *prop_name;
        const void *prop_value;
        int prop_len;

        prop = fdt_get_property_by_offset(fdt, property_offset, &prop_len);
        if (prop == NULL) {
            fprintf(stderr, "Error getting property by offset\n");
            return;
        }
        prop_name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
        prop_value = prop->data;

        for (int i = 0; i < depth + 1; ++i) {
            fprintf(output, "  ");
        }
        fprintf(output, "%s: ", prop_name);

        // 打印属性值
        for (int i = 0; i < prop_len; ++i) {
            fprintf(output, "%02x ", ((const unsigned char *)prop_value)[i]);
        }
        fprintf(output, "\n");
    }

    // 遍历子节点
    fdt_for_each_subnode(next_offset, fdt, offset) {
        parse_node(fdt, next_offset, depth + 1, output);
    }
}

int main(int argc, char *argv[]) {
    if (argc < 3) {
        fprintf(stderr, "Usage: %s <path to dtb file> <output file>\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *dtb_path = argv[1];
    const char *output_path = argv[2];

    FILE *file = fopen(dtb_path, "rb");
    if (file == NULL) {
        perror("Error opening file");
        return EXIT_FAILURE;
    }

    // 获取文件大小
    fseek(file, 0, SEEK_END);
    long dtb_size = ftell(file);
    fseek(file, 0, SEEK_SET);

    // 读取文件内容到内存中
    void *dtb = malloc(dtb_size);
    if (dtb == NULL) {
        perror("Error allocating memory");
        fclose(file);
        return EXIT_FAILURE;
    }
    fread(dtb, 1, dtb_size, file);
    fclose(file);

    // 检查设备树的有效性
    if (fdt_check_header(dtb) != 0) {
        fprintf(stderr, "Invalid device tree header\n");
        free(dtb);
        return EXIT_FAILURE;
    }

    // 打开输出文件
    FILE *output = fopen(output_path, "w");
    if (output == NULL) {
        perror("Error opening output file");
        free(dtb);
        return EXIT_FAILURE;
    }

    // 解析设备树
    parse_node(dtb, 0, 0, output);

    free(dtb);
    fclose(output);
    return EXIT_SUCCESS;
}

